package com.ophelisis.actions.system;

import java.io.File;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import com.ophelisis.common.consts.ConstCode.AuthLevelType;
import com.ophelisis.common.consts.ConstPath;
import com.ophelisis.common.util.CryptUtils;
import com.ophelisis.common.util.DateUtil;
import com.ophelisis.common.util.StringUtil;
import com.ophelisis.persistence.dao.LogoDAO;
import com.ophelisis.persistence.dao.MenuAuthDAO;
import com.ophelisis.persistence.dao.MenuDAO;
import com.ophelisis.persistence.dao.MenuGroupDAO;
import com.ophelisis.persistence.dao.PortalUserDAO;
import com.ophelisis.persistence.domain.MenuAuthVO;
import com.ophelisis.persistence.domain.MenuGroupVO;
import com.ophelisis.persistence.domain.MenuVO;
import com.ophelisis.persistence.domain.PortalUserVO;

/** <pre>
 * Class : com.ophelisis.actions.system.Login / Login.java
 * 	Define Class Object : 
 * <br>
 * </pre>
 * @author hlee / apexcns,Inc.
 * @version 1.0
 * @see javadoc
 * @since 2013. 01. 17.
 */
@Controller
@SessionAttributes({"userId", "userNm", "userLevel", "userUrl", "menuGroupList", "menuList", "menuAuthList", "logoFileName"})
public class Login {
	@Autowired
	MenuGroupDAO menuGroupDAO;
	
	@Autowired
	MenuDAO menuDAO;
	
	@Autowired
	MenuAuthDAO menuAuthDAO;
	
	@Autowired
	PortalUserDAO userDAO;
	
	@Autowired
	LogoDAO logoDAO;
	
	private List<MenuGroupVO> menuGroupList;
	private List<MenuVO> menuList;
	private List<MenuAuthVO> menuAuthList;
	private String logoFileName;
	
	private Log log = LogFactory.getLog(this.getClass());
	private static final String _LogPrefixStr = "Login Log> ";
	
	@RequestMapping(value="login.action")
	public ModelAndView login(
			@RequestParam (value="userId", defaultValue="") String userId,
			@RequestParam (value="userPw", defaultValue="") String userPw,
			@RequestParam (value="userUrl", defaultValue="") String userUrl) throws Exception {
		ModelAndView mav = new ModelAndView();
		
		log.debug(_LogPrefixStr + "|" + "------------------------------------------------------------------------------------");
		log.debug(_LogPrefixStr + "|" + " Login called !!!");
		log.debug(_LogPrefixStr + "|" + "------------------------------------------------------------------------------------");
		
		File directory = new File(ConstPath.rootPath);
		if (!directory.isDirectory()) {
			directory.mkdirs();
		}
		
		String loginMessage = null;
		
		boolean isGlobalAdmin = false; // Global Admin User 여부
		boolean contSession = false;
		
		if (userId.equals("")) {
			mav.setViewName("/WEB-INF/jsp/system/login.jsp");
			return mav;
		}

		try {
			contSession = true;
			/*
			 * 시스템 기본 사용자
			 * [사용자 권한 구분] :: 1 ~ 9 
			 * 		sysadmin :: 9 :: 통합관리자  :: Full Embbeded Administrator 
			 * 		admin :: 7 :: 운영관리자  :: Super Administrator
			 * 		subadmin :: 5 :: 서브관리자  :: Sub Administrator
			 * 		manager :: 3 :: 일반관리자  ::  Manager
			 * 		test :: 1 :: 일반사용자  ::  User
			 */
			PortalUserVO userVO;
			isGlobalAdmin = isSystemAdminUser(userId, userPw);
			if (isGlobalAdmin) {
				userVO = getDefaultUserInfo(userId, userPw, AuthLevelType.sysadmin.getCode());
			} else {
				userVO = getUserInfo(userId, userPw); // DB에서 사용자 정보 조회
			}

			mav.addObject("preUserId", userId);

			if (userVO == null) { 
				loginMessage = "존재하지 않는 사용자이거나 잘못된 비밀번호입니다.";

				mav.setViewName("/WEB-INF/jsp/system/login.jsp");
				mav.addObject("loginMessage", loginMessage);
				return mav;
			} else if (!isGlobalAdmin) {
				boolean isUserPwCheckOk = true;
				
				isUserPwCheckOk = isMatchuserVO(userPw, userVO.getUserPassword()); // Password 비교
				if (!isUserPwCheckOk) {
					loginMessage = "잘못된 비밀번호입니다. [ userId :: " + userId + " ]";

					mav.setViewName("/WEB-INF/jsp/system/login.jsp");
					mav.addObject("loginMessage", loginMessage);
					return mav;
				}

				userVO.setLoginDatetime(DateUtil.nowDateString());
				userVO = updateUserInfo(userVO);
			}

			Map<String, Object> params = new HashMap<String, Object>();
			
			menuGroupList = menuGroupDAO.getMenuGroupList(params);
			menuList = menuDAO.getMenuList(params);
			
			params.clear();
			params.put("authLevel", userVO.getUserAuth());
			menuAuthList = menuAuthDAO.getMenuAuthList(params);

			params.clear();
			params.put("useYn", "Y");
			logoFileName = logoDAO.getLogoList(params).get(0).getLogoFileNew();

			if (contSession) {
				mav.addObject("userUrl", userUrl);
			} else {
				mav.addObject("userUrl", "");
			}
			
			mav.addObject("userId", userVO.getUserId());
			mav.addObject("userNm", userVO.getUserNm());
			mav.addObject("userLevel", userVO.getUserAuth());
			mav.addObject("menuGroupList", menuGroupList);
			mav.addObject("menuList", menuList);
			mav.addObject("menuAuthList", menuAuthList);
			mav.addObject("logoFileName", logoFileName);
		} catch (Exception e) {
			log.error("알 수 없는 오류", e);
			loginMessage = "알 수 없는 오류입니다. [ userId :: " + userId + " ]";

			mav.setViewName("/WEB-INF/jsp/system/login.jsp");
			mav.addObject("loginMessage", loginMessage);
			return mav;
		}
		mav.setViewName("/WEB-INF/jsp/system/login_ok.jsp");
		return mav;
	}

	/**
	 * 통합관리자 정보 확인
	 * 		sysadmin / sysadmin@1234 :: 9 :: 통합관리자  :: Full Embbeded SuperUser 
	 */
	private boolean isSystemAdminUser(String userId, String userPw) {
		if (userId.equals("sysadmin") && userPw.equals("sysadmin@1234")) {
			log.info("통합관리자 정보가  입력 되었습니다. [ userId :: " + userId + " ]");
			return true;
		}
		return false;
	}

	/**
	 * DB 사용자 정보 획득
	 */
	private PortalUserVO getUserInfo(String userId, String userEncPw) { // 암호화된 Password 정보 존재
		PortalUserVO userInfo = null;
		
		try {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("userId", userId);
			if (!StringUtil.isEmpty(userEncPw)) 
				params.put("userPw", userEncPw);
			params.put("userType", "0");

			userInfo = userDAO.getPortalUserInfo(params);
		} catch (SQLException e1) {
			log.error("DB 사용자 정보 획득 failed!, userId=" + userId, e1);
		} catch (DataAccessException e2) {
			log.error("DB 사용자 정보 획득 failed!, userId=" + userId, e2);
		} catch (Exception e3) {
			log.error("DB 사용자 정보 획득 failed!, userId=" + userId, e3);
		}
		
		return userInfo;
	}
	
	/**
	 * DB 사용자 정보 업데이트
	 */
	private PortalUserVO updateUserInfo(PortalUserVO encUser) { // 암호화된 Password 정보 존재
		try {
			userDAO.setPortalUserModify(encUser);

		} catch (SQLException e1) {
			log.error("DB 사용자 정보 업데이트 failed!, " + encUser.toString(), e1);
		} catch (DataAccessException e2) {
			log.error("DB 사용자 정보 업데이트 failed!, " + encUser.toString(), e2);
		} catch (Exception e3) {
			log.error("DB 사용자 정보 업데이트 failed!, " + encUser.toString(), e3);
		}
		
		return encUser;
	}
	
	/**
	 * Password 비교 
	 * @param getUserPw 입력 정보
	 * @param inEncUserPw DB 정보
	 * @return boolean
	 */
	private boolean isMatchuserVO(String getUserPw, String inEncUserPw) {
		if (getUserPw == null)
			return false;

		// Password 복호화 후 비교
		String decPw = CryptUtils.decrypt(inEncUserPw);
		log.debug("=====> in Password 복호화, " + inEncUserPw + " : " + decPw);

		if (!getUserPw.equals(decPw))
			return false;

		return true;
	}

	/**
	 * 기본 사용자 획득 처리
	 */
	private PortalUserVO getDefaultUserInfo(String userId, String userPw, String pAuthLevel) {
		PortalUserVO userVO = null;

		String authLevel = StringUtil.nvl(pAuthLevel, "0");

		userVO = new PortalUserVO();
		userVO.setUserId(userId);
		userVO.setUserPassword(userPw);
		userVO.setUserNm(AuthLevelType.get(pAuthLevel).getDescription());
		userVO.setUserAuth(authLevel);

		return userVO;
	}
}
